/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pa165.dominatingspecies.dao.impl;

import java.util.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.springframework.stereotype.Repository;
import pa165.dominating.species.dao.ElementDao;
import pa165.dominating.species.entities.Element;
import pa165.dominating.species.enums.ElementType;
import pa165.dominating.species.exceptions.DataStorageException;
import pa165.dominating.species.exceptions.EntityException;

/**
 *
 * @author Ondrej Prazak
 */
@Repository
public class ElementDaoImpl implements ElementDao {

    private EntityManagerFactory emf;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    @Override
    public void createElement(Element element) {
        EntityManager em = getEntityManager();
        try {
            nullArgumentsHelper(element);
            em.getTransaction().begin();
            List<Element> found = em.createQuery("SELECT e FROM Element e WHERE e.type = :type").setParameter("type", element.getType()).getResultList();
            if (!found.isEmpty()) {
                throw new EntityException("Element with given type already exists - cannot create");
            }
            em.persist(element);
            em.getTransaction().commit();
        } catch (Exception ex) {
            throw new DataStorageException("An error has occurred while creating new Element", ex);
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    @Override
    public void deleteElement(Element element) {
        EntityManager em = getEntityManager();
        nullArgumentsHelper(element);
        if (element.getId() == null) {
            throw new EntityException("Id of given element is null");
        }
        try {
            em.getTransaction().begin();
            Element ele = em.find(Element.class, element.getId());
            em.remove(ele);
            em.getTransaction().commit();
        } catch (Exception ex) {
            throw new DataStorageException("An error has occurred while deleting new Element", ex);
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    @Override
    public Element getElementById(Long id) {
        EntityManager em = getEntityManager();
        if (id == null) {
            throw new EntityException("id is null");
        }
        Element ele;
        try {
            em.getTransaction().begin();
            ele = em.find(Element.class, id);
            em.getTransaction().commit();
        } catch (Exception ex) {
            throw new DataStorageException("An error has occurred while getting Element by id: " + id, ex);
        } finally {
            if (em != null) {
                em.close();
            }
        }
        return ele;
    }

    @Override
    public List<Element> getAllElements() {
        EntityManager em = getEntityManager();
        List<Element> found;
        try {
            em.getTransaction().begin();
            found = em.createQuery("SELECT e FROM Element e").getResultList();
            em.getTransaction().commit();
        } catch (Exception ex) {
            throw new DataStorageException("An error has occurred while getting all Elements", ex);
        } finally {
            if (em != null) {
                em.close();
            }
        }
        return found;
    }

    @Override
    public void updateElement(Element element) {
        EntityManager em = getEntityManager();
        nullArgumentsHelper(element);
        try {
            em.getTransaction().begin();
            Element ele = em.find(Element.class, element.getId());
            ele.setDescription(element.getDescription());
            List<Element> found = getAllElements();
            for (Element item : found) {
                if ((item.getType() == ele.getType()) && (item.getId() != ele.getId())) {
                    throw new EntityException("Element with given type already exists - cannot update");
                }
            }
            ele.setType(element.getType());
            em.getTransaction().commit();
        } catch (Exception ex) {
            throw new DataStorageException("An error has occurred while updating Element", ex);
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public Element getElementByType(ElementType type) {
        EntityManager em = getEntityManager();
        if (type == null) {
            throw new EntityException("type is null, cannot retrieve element");
        }
        List<Element> found;
        try {
            em.getTransaction().begin();
            found = em.createQuery("SELECT e FROM Element e WHERE e.type = :type").setParameter("type", type).getResultList();
            if (found.isEmpty()) {
                throw new EntityException("Element with given type adoes not exist");
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            throw new DataStorageException("An error has occurred while creating new Element", ex);
        } finally {
            if (em != null) {
                em.close();
            }

        }
        return found.get(0);
    }

    public EntityManagerFactory getEmf() {
        return emf;
    }

    public void setEmf(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public void nullArgumentsHelper(Element ele) {
        if (ele == null) {
            throw new EntityException("Element is null");
        }
        if (ele.getType() == null) {
            throw new EntityException("Element type is null");
        }
    }
}
